package de.hsb.ai.util.map;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.jgrapht.Graph;
import org.jgrapht.GraphPath;
import org.jgrapht.alg.FloydWarshallShortestPaths;

public class MapInfo<V, E> {
	
	public final int maxEdges, minEdges;
	public final double avgEdges, medEdges;
	
	private final FloydWarshallShortestPaths<V, E> shortestPaths;
	
	public MapInfo(Graph<V, E> graph) {
		Set<V> verices = graph.vertexSet();
		int[] edgeCount = new int[verices.size()];
		int i = 0, max = Integer.MIN_VALUE, min = Integer.MAX_VALUE, sum = 0;
		for (V v : verices) {
			int numEdges = graph.edgesOf(v).size();
			if (numEdges > 0) {
				max = Math.max(max, numEdges);
				min = Math.min(min, numEdges);
				edgeCount[i++] = numEdges;
			}
			sum += numEdges;
		}
		
		maxEdges = max;
		minEdges = min;
		avgEdges = sum / (double)i;
		
		Arrays.sort(edgeCount);
		Map<Integer, Integer> map = new HashMap<Integer, Integer>();
		for (Integer c : edgeCount) {
			Integer n = map.get(c);
			map.put(c, n == null ? 1 : n + 1);
		}
		medEdges = median(edgeCount);
		
		shortestPaths = new FloydWarshallShortestPaths<V, E>(graph);
	}
	
	private final double median(int[] m) {
		int middle = m.length/2;  // subscript of middle element
		if (m.length%2 == 1) {
			// Odd number of elements -- return the middle one.
			return m[middle];
		} else {
			// Even number -- return average of middle two
			// Must cast the numbers to double before dividing.
			return (m[middle-1] + m[middle]) / 2D;
		}
	}
	
	public double getConnectivity(double edges) {
		double delta = (edges - minEdges) / (maxEdges - minEdges);
		return Math.round(delta * 10) / 10D;
	}
	
	/**
	 * @see org.jgrapht.alg.FloydWarshallShortestPaths#getShortestPathsCount()
	 */
	public int getShortestPathsCount() {
		return shortestPaths.getShortestPathsCount();
	}

	/**
	 * @see org.jgrapht.alg.FloydWarshallShortestPaths#shortestDistance(java.lang.Object, java.lang.Object)
	 */
	public double shortestDistance(V a, V b) {
		return shortestPaths.shortestDistance(a, b);
	}

	/**
	 * @see org.jgrapht.alg.FloydWarshallShortestPaths#getDiameter()
	 */
	public double getDiameter() {
		return shortestPaths.getDiameter();
	}

	/**
	 * @see org.jgrapht.alg.FloydWarshallShortestPaths#getShortestPath(java.lang.Object, java.lang.Object)
	 */
	public GraphPath<V, E> getShortestPath(V a, V b) {
		return shortestPaths.getShortestPath(a, b);
	}

	/**
	 * @see org.jgrapht.alg.FloydWarshallShortestPaths#getShortestPaths(java.lang.Object)
	 */
	public List<GraphPath<V, E>> getShortestPaths(V v) {
		return shortestPaths.getShortestPaths(v);
	}

	@Override
	public String toString() {
		return new StringBuilder("Map Info: ")
		.append(" max: ").append(maxEdges)
		.append(" min: ").append(minEdges)
		.append(" avg: ").append(avgEdges)
		.append(" med: ").append(medEdges)
		.toString();
	}
	
}